# src/utils/helpers.py
import numpy as np
import pandas as pd
import logging
from typing import Any, Dict, List
import json
from datetime import datetime

def setup_logging(level: str = "INFO") -> logging.Logger:
    """设置日志"""
    logging.basicConfig(
        level=getattr(logging, level),
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
    return logging.getLogger(__name__)

def validate_weights(weights: np.ndarray, tolerance: float = 1e-6) -> bool:
    """验证权重向量"""
    # 检查是否为非负
    if np.any(weights < 0):
        return False
    
    # 检查是否和为1
    if abs(np.sum(weights) - 1.0) > tolerance:
        return False
    
    return True

def normalize_weights(weights: np.ndarray) -> np.ndarray:
    """归一化权重"""
    weights = np.maximum(weights, 0)  # 确保非负
    total = np.sum(weights)
    
    if total > 0:
        return weights / total
    else:
        # 如果所有权重都为0，返回等权重
        return np.ones(len(weights)) / len(weights)

def calculate_portfolio_concentration(weights: np.ndarray) -> float:
    """计算投资组合集中度（HHI指数）"""
    return np.sum(weights ** 2)

def load_config(config_path: str) -> Dict[str, Any]:
    """加载配置文件"""
    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        logging.error(f"加载配置文件失败: {e}")
        return {}

def save_results(results: Dict[str, Any], filepath: str) -> None:
    """保存结果到文件"""
    try:
        # 处理numpy数组
        def convert_numpy(obj):
            if isinstance(obj, np.ndarray):
                return obj.tolist()
            elif isinstance(obj, np.floating):
                return float(obj)
            elif isinstance(obj, np.integer):
                return int(obj)
            elif isinstance(obj, datetime):
                return obj.isoformat()
            return obj
        
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(results, f, default=convert_numpy, indent=2, ensure_ascii=False)
            
        logging.info(f"结果已保存至: {filepath}")
        
    except Exception as e:
        logging.error(f"保存结果失败: {e}")
        